home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / src / moveres.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-03-30  |  62.0 KB  |  2,273 lines

  1. /*
  2.  *  Window Maker window manager
  3.  * 
  4.  *  Copyright (c) 1997, 1998, 1999 Alfredo K. Kojima
  5.  * 
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 
  19.  *  USA.
  20.  */
  21.  
  22. #include "wconfig.h"
  23.  
  24. #include <X11/Xlib.h>
  25. #include <X11/Xutil.h>
  26. #include <X11/keysym.h>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <unistd.h>
  30. #include <string.h>
  31.  
  32. #include "WindowMaker.h"
  33. #include "wcore.h"
  34. #include "framewin.h"
  35. #include "window.h"
  36. #include "client.h"
  37. #include "icon.h"
  38. #include "dock.h"
  39. #include "funcs.h"
  40. #include "actions.h"
  41. #include "workspace.h"
  42.  
  43. #include "geomview.h"
  44.  
  45.  
  46. #ifdef KWM_HINTS
  47. #include "kwm.h"
  48. #endif
  49.  
  50. /* How many different types of geometry/position
  51.  display thingies are there? */
  52. #define NUM_DISPLAYS 4
  53.  
  54. #define LEFT            1
  55. #define RIGHT           2
  56. #define HORIZONTAL      (LEFT|RIGHT)
  57. #define UP              4
  58. #define DOWN            8
  59. #define VERTICAL        (UP|DOWN)
  60.  
  61. /****** Global Variables ******/
  62. extern Time LastTimestamp;
  63.  
  64. extern Cursor wCursor[WCUR_LAST];
  65.  
  66. extern WPreferences wPreferences;
  67.  
  68. extern Atom _XA_WM_PROTOCOLS;
  69.  
  70.  
  71.  
  72. /*
  73.  *----------------------------------------------------------------------
  74.  * checkMouseSamplingRate-
  75.  *      For lowering the mouse motion sampling rate for machines where
  76.  * it's too high (SGIs). If it returns False then the event should be
  77.  * ignored.
  78.  *----------------------------------------------------------------------
  79.  */
  80. static Bool
  81. checkMouseSamplingRate(XEvent *ev)
  82. {
  83.     static Time previousMotion = 0;
  84.     
  85.     if (ev->type == MotionNotify) {
  86.         if (ev->xmotion.time - previousMotion < DELAY_BETWEEN_MOUSE_SAMPLING) {
  87.             return False;
  88.         } else {
  89.             previousMotion = ev->xmotion.time;
  90.         }
  91.     }
  92.     return True;
  93. }
  94.  
  95.  
  96.  
  97. /*
  98.  *----------------------------------------------------------------------
  99.  * moveGeometryDisplayCentered
  100.  *
  101.  * routine that moves the geometry/position window on scr so it is
  102.  * centered over the given coordinates (x,y). Also the window position
  103.  * is clamped so it stays on the screen at all times.
  104.  *----------------------------------------------------------------------
  105.  */
  106. static void
  107. moveGeometryDisplayCentered(WScreen *scr, int x, int y)
  108. {
  109.     unsigned int w = WMWidgetWidth(scr->gview);
  110.     unsigned int h = WMWidgetHeight(scr->gview);
  111.     
  112.     x -= w / 2;
  113.     y -= h / 2;
  114.     
  115.     if (x < 1)
  116.     x = 1;
  117.     else if (x > (scr->scr_width - w - 3))
  118.     x = scr->scr_width - w - 3;
  119.     
  120.     if (y < 1)
  121.     y = 1;
  122.     else if (y > (scr->scr_height - h - 3))
  123.     y = scr->scr_height - h - 3;
  124.  
  125.     WMMoveWidget(scr->gview, x, y);
  126. }
  127.  
  128.  
  129. static void
  130. showPosition(WWindow *wwin, int x, int y)
  131. {
  132.     WScreen *scr = wwin->screen_ptr;
  133.  
  134.     if (wPreferences.move_display == WDIS_NEW) {
  135. #if 0
  136.         int width = wwin->frame->core->width;
  137.         int height = wwin->frame->core->height;
  138.  
  139.     GC lgc = scr->line_gc;
  140.     XSetForeground(dpy, lgc, scr->line_pixel);
  141.     sprintf(num, "%i", x);
  142.  
  143.     XDrawLine(dpy, scr->root_win, lgc, 0, y-1, scr->scr_width, y-1);
  144.     XDrawLine(dpy, scr->root_win, lgc, 0, y+height+2, scr->scr_width,
  145.           y+height+2);
  146.     XDrawLine(dpy, scr->root_win, lgc, x-1, 0, x-1, scr->scr_height);
  147.     XDrawLine(dpy, scr->root_win, lgc, x+width+2, 0, x+width+2,
  148.           scr->scr_height);
  149. #endif
  150.     } else {
  151.     WSetGeometryViewShownPosition(scr->gview, x, y);
  152.     }
  153. }
  154.  
  155.  
  156. static void
  157. cyclePositionDisplay(WWindow *wwin, int x, int y, int w, int h)
  158. {
  159.     WScreen *scr = wwin->screen_ptr;
  160.  
  161.     wPreferences.move_display++;
  162.     wPreferences.move_display %= NUM_DISPLAYS;
  163.  
  164.     if (wPreferences.move_display == WDIS_NEW) {
  165.     WMUnmapWidget(scr->gview);
  166.     } else {
  167.     if (wPreferences.move_display == WDIS_CENTER) {
  168.         moveGeometryDisplayCentered(scr,
  169.                     scr->scr_width/2, scr->scr_height/2);
  170.     } else if (wPreferences.move_display == WDIS_TOPLEFT) {
  171.         moveGeometryDisplayCentered(scr, 1, 1);
  172.     } else if (wPreferences.move_display == WDIS_FRAME_CENTER) {
  173.         moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
  174.     }
  175.     WMMapWidget(scr->gview);
  176.     }
  177. }
  178.  
  179.  
  180. static void
  181. mapPositionDisplay(WWindow *wwin, int x, int y, int w, int h)
  182. {
  183.     WScreen *scr = wwin->screen_ptr;
  184.     
  185.     if (wPreferences.move_display == WDIS_NEW) {
  186.     return;
  187.     } else if (wPreferences.move_display == WDIS_CENTER) {
  188.     moveGeometryDisplayCentered(scr, scr->scr_width / 2,
  189.                     scr->scr_height / 2);
  190.     } else if (wPreferences.move_display == WDIS_TOPLEFT) {
  191.     moveGeometryDisplayCentered(scr, 1, 1);
  192.     } else if (wPreferences.move_display == WDIS_FRAME_CENTER) {
  193.     moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
  194.     }
  195.     WMMapWidget(scr->gview);
  196.     WSetGeometryViewShownPosition(scr->gview, x, y);
  197. }
  198.  
  199.  
  200. static void
  201. showGeometry(WWindow *wwin, int x1, int y1, int x2, int y2, int direction)
  202. {
  203.     WScreen *scr = wwin->screen_ptr;
  204.     Window root = scr->root_win;
  205.     GC gc = scr->line_gc;
  206.     int ty, by, my, x, y, mx, s;
  207.     char num[16];
  208.     XSegment segment[4];
  209.     int fw, fh;
  210.  
  211.     ty = y1 + wwin->frame->top_width;
  212.     by = y2 - wwin->frame->bottom_width;
  213.     fw = WMWidthOfString(scr->info_text_font, "8888", 4);
  214.     fh = WMFontHeight(scr->info_text_font);
  215.  
  216.     if (wPreferences.size_display == WDIS_NEW) {
  217.     XSetForeground(dpy, gc, scr->line_pixel);
  218.     
  219.     /* vertical geometry */
  220.     if (((direction & LEFT) && (x2 < scr->scr_width - fw)) || (x1 < fw)) {
  221.         x = x2;
  222.         s = -15;
  223.     } else {
  224.         x = x1;
  225.         s = 15;
  226.     }
  227.     my = (ty + by) / 2;
  228.     
  229.     /* top arrow */
  230.     /* end bar */
  231.     segment[0].x1 = x - (s + 6);  segment[0].y1 = ty;
  232.     segment[0].x2 = x - (s - 10); segment[0].y2 = ty;
  233.     
  234.     /* arrowhead */
  235.     segment[1].x1 = x - (s - 2); segment[1].y1 = ty + 1;
  236.     segment[1].x2 = x - (s - 5); segment[1].y2 = ty + 7;
  237.     
  238.     segment[2].x1 = x - (s - 2); segment[2].y1 = ty + 1;
  239.     segment[2].x2 = x - (s + 1); segment[2].y2 = ty + 7;
  240.     
  241.     /* line */
  242.     segment[3].x1 = x - (s - 2); segment[3].y1 = ty + 1;
  243.     segment[3].x2 = x - (s - 2); segment[3].y2 = my - fh/2 - 1;
  244.     
  245.     XDrawSegments(dpy, root, gc, segment, 4);
  246.     
  247.     /* bottom arrow */
  248.     /* end bar */
  249.     segment[0].y1 = by;
  250.     segment[0].y2 = by;
  251.     
  252.     /* arrowhead */
  253.     segment[1].y1 = by - 1;
  254.     segment[1].y2 = by - 7;
  255.     
  256.     segment[2].y1 = by - 1;
  257.     segment[2].y2 = by - 7;
  258.     
  259.     /* line */
  260.     segment[3].y1 = my + fh/2 + 2;
  261.     segment[3].y2 = by - 1;
  262.     
  263.     XDrawSegments(dpy, root, gc, segment, 4);
  264.     
  265.     sprintf(num, "%i", (by - ty - wwin->normal_hints->base_height) /
  266.         wwin->normal_hints->height_inc);
  267.     fw = WMWidthOfString(scr->info_text_font, num, strlen(num));
  268.     
  269.     /* XSetForeground(dpy, gc, scr->window_title_pixel[WS_UNFOCUSED]); */
  270.     
  271.     /* Display the height. */
  272.     WMDrawString(scr->wmscreen, root, gc, scr->info_text_font, 
  273.               x - s + 3 - fw/2, my - fh/2 + 1, num, strlen(num));
  274.     XSetForeground(dpy, gc, scr->line_pixel);
  275.     /* horizontal geometry */
  276.     if (y1 < 15) {
  277.         y = y2;
  278.         s = -15;
  279.     } else {
  280.         y = y1;
  281.         s = 15;
  282.     }
  283.     mx = x1 + (x2 - x1)/2;
  284.     sprintf(num, "%i", (x2 - x1 - wwin->normal_hints->base_width) /
  285.         wwin->normal_hints->width_inc);
  286.     fw = WMWidthOfString(scr->info_text_font, num, strlen(num));
  287.     
  288.     /* left arrow */
  289.     /* end bar */
  290.     segment[0].x1 = x1; segment[0].y1 = y - (s + 6);
  291.     segment[0].x2 = x1; segment[0].y2 = y - (s - 10);
  292.     
  293.     /* arrowhead */
  294.     segment[1].x1 = x1 + 7; segment[1].y1 = y - (s + 1);
  295.     segment[1].x2 = x1 + 1; segment[1].y2 = y - (s - 2);
  296.     
  297.     segment[2].x1 = x1 + 1; segment[2].y1 = y - (s - 2);
  298.     segment[2].x2 = x1 + 7; segment[2].y2 = y - (s - 5);
  299.     
  300.     /* line */
  301.     segment[3].x1 = x1 + 1; segment[3].y1 = y - (s - 2);
  302.     segment[3].x2 = mx - fw/2 - 2; segment[3].y2 = y - (s - 2);
  303.     
  304.     XDrawSegments(dpy, root, gc, segment, 4);
  305.     
  306.     /* right arrow */
  307.     /* end bar */
  308.     segment[0].x1 = x2 + 1;
  309.     segment[0].x2 = x2 + 1;
  310.     
  311.     /* arrowhead */
  312.     segment[1].x1 = x2 - 6;
  313.     segment[1].x2 = x2;
  314.     
  315.     segment[2].x1 = x2;
  316.     segment[2].x2 = x2 - 6;
  317.     
  318.     /* line */
  319.     segment[3].x1 = mx + fw/2 + 2;
  320.     segment[3].x2 = x2;
  321.     
  322.     XDrawSegments(dpy, root, gc, segment, 4);
  323.     
  324.     /* XSetForeground(dpy, gc, scr->window_title_pixel[WS_UNFOCUSED]); */
  325.     
  326.     /* Display the width. */
  327.     WMDrawString(scr->wmscreen, root, gc, scr->info_text_font,
  328.              mx - fw/2 + 1, y - s - fh/2 + 1, num, strlen(num));
  329.     } else {
  330.     WSetGeometryViewShownSize(scr->gview,
  331.                   (x2 - x1 - wwin->normal_hints->base_width)
  332.                   / wwin->normal_hints->width_inc,
  333.                   (by - ty - wwin->normal_hints->base_height)
  334.                   / wwin->normal_hints->height_inc);
  335.     }
  336. }
  337.  
  338.  
  339. static void
  340. cycleGeometryDisplay(WWindow *wwin, int x, int y, int w, int h, int dir)
  341. {
  342.     WScreen *scr = wwin->screen_ptr;
  343.     
  344.     wPreferences.size_display++;
  345.     wPreferences.size_display %= NUM_DISPLAYS;
  346.     
  347.     if (wPreferences.size_display == WDIS_NEW) {
  348.     WMUnmapWidget(scr->gview);
  349.     } else {
  350.     if (wPreferences.size_display == WDIS_CENTER) {
  351.         moveGeometryDisplayCentered(scr,
  352.                     scr->scr_width / 2, scr->scr_height / 2);
  353.     } else if (wPreferences.size_display == WDIS_TOPLEFT) {
  354.         moveGeometryDisplayCentered(scr, 1, 1);
  355.     } else if (wPreferences.size_display == WDIS_FRAME_CENTER) {
  356.         moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
  357.     }
  358.     WMMapWidget(scr->gview);
  359.     showGeometry(wwin, x, y, x + w, y + h, dir);
  360.     }
  361. }
  362.  
  363.  
  364. static void
  365. mapGeometryDisplay(WWindow *wwin, int x, int y, int w, int h)
  366. {
  367.     WScreen *scr = wwin->screen_ptr;
  368.     
  369.     if (wPreferences.size_display == WDIS_NEW)
  370.     return;
  371.     
  372.     if (wPreferences.size_display == WDIS_CENTER) {
  373.     moveGeometryDisplayCentered(scr, scr->scr_width / 2,
  374.                     scr->scr_height / 2);
  375.     } else if (wPreferences.size_display == WDIS_TOPLEFT) {
  376.     moveGeometryDisplayCentered(scr, 1, 1);
  377.     } else if (wPreferences.size_display == WDIS_FRAME_CENTER) {
  378.     moveGeometryDisplayCentered(scr, x + w/2, y + h/2);
  379.     }
  380.     WMMapWidget(scr->gview);
  381.     showGeometry(wwin, x, y, x + w, y + h, 0);
  382. }
  383.  
  384.  
  385.  
  386. static void
  387. doWindowMove(WWindow *wwin, WMBag *bag, int dx, int dy)
  388. {
  389.     WWindow *tmpw;
  390.     int x, y;
  391.     int scr_width = wwin->screen_ptr->scr_width;
  392.     int scr_height = wwin->screen_ptr->scr_height;
  393.  
  394.     if (!bag || !WMGetBagItemCount(bag)) {
  395.         wWindowMove(wwin, wwin->frame_x + dx, wwin->frame_y + dy);
  396.     } else {
  397.     int i;
  398.     for (i = 0; i < WMGetBagItemCount(bag); i++) {
  399.         tmpw = WMGetFromBag(bag, i);
  400.         x = tmpw->frame_x + dx;
  401.         y = tmpw->frame_y + dy;
  402.         
  403.         /* don't let windows become unreachable */
  404.         
  405.         if (x + (int)tmpw->frame->core->width < 20)
  406.         x = 20 - (int)tmpw->frame->core->width;
  407.         else if (x + 20 > scr_width)
  408.         x = scr_width - 20;
  409.  
  410.         if (y + (int)tmpw->frame->core->height < 20)
  411.         y = 20 - (int)tmpw->frame->core->height;
  412.         else if (y + 20 > scr_height)
  413.         y = scr_height - 20;
  414.         
  415.          wWindowMove(tmpw, x, y);
  416.     }
  417.     }
  418. }
  419.  
  420.  
  421. static void
  422. drawTransparentFrame(WWindow *wwin, int x, int y, int width, int height)
  423. {
  424.     Window root = wwin->screen_ptr->root_win;
  425.     GC gc = wwin->screen_ptr->frame_gc;
  426.     int h = 0;
  427.     int bottom = 0;
  428.     
  429.     if (!WFLAGP(wwin, no_titlebar) && !wwin->flags.shaded) {
  430.     h = WMFontHeight(wwin->screen_ptr->title_font) + (wPreferences.window_title_clearance + TITLEBAR_EXTEND_SPACE) * 2;
  431.     }
  432.     if (!WFLAGP(wwin, no_resizebar) && !wwin->flags.shaded) {
  433.     /* Can't use wwin-frame->bottom_width because, in some cases 
  434.      (e.g. interactive placement), frame does not point to anything. */
  435.     bottom = RESIZEBAR_HEIGHT - 1;
  436.     } 
  437.     XDrawRectangle(dpy, root, gc, x, y, width + 1, height + 1);
  438.     
  439.     if (h > 0) {
  440.     XDrawLine(dpy, root, gc, x + 1, y + h, x + width + 1, y + h); 
  441.     }
  442.     if (bottom > 0) {
  443.     XDrawLine(dpy, root, gc, x + 1,
  444.           y + height - bottom,
  445.           x + width + 1,
  446.           y + height - bottom);
  447.     }
  448. }
  449.  
  450.  
  451. static void
  452. drawFrames(WWindow *wwin, WMBag *bag, int dx, int dy)
  453. {
  454.     WWindow *tmpw;
  455.     int scr_width = wwin->screen_ptr->scr_width;
  456.     int scr_height = wwin->screen_ptr->scr_height;
  457.     int x, y;
  458.     
  459.     if (!bag) {
  460.  
  461.         x = wwin->frame_x + dx;
  462.         y = wwin->frame_y + dy;
  463.  
  464.     drawTransparentFrame(wwin, x, y,
  465.                  wwin->frame->core->width, 
  466.                  wwin->frame->core->height);
  467.     
  468.     } else {
  469.     int i;
  470.     for (i = 0; i < WMGetBagItemCount(bag); i++) {
  471.         tmpw = WMGetFromBag(bag, i);
  472.         x = tmpw->frame_x + dx;
  473.         y = tmpw->frame_y + dy;
  474.         
  475.         /* don't let windows become unreachable */
  476.         
  477.         if (x + (int)tmpw->frame->core->width < 20)
  478.         x = 20 - (int)tmpw->frame->core->width;
  479.         else if (x + 20 > scr_width)
  480.         x = scr_width - 20;
  481.         
  482.         if (y + (int)tmpw->frame->core->height < 20)
  483.         y = 20 - (int)tmpw->frame->core->height;
  484.         else if (y + 20 > scr_height)
  485.         y = scr_height - 20;
  486.         
  487.         drawTransparentFrame(tmpw, x, y, tmpw->frame->core->width,
  488.                  tmpw->frame->core->height);
  489.     }
  490.     }
  491. }
  492.  
  493.  
  494.  
  495. static void
  496. flushMotion()
  497. {
  498.     XEvent ev;
  499.  
  500.     XSync(dpy, False);
  501.     while (XCheckMaskEvent(dpy, ButtonMotionMask, &ev)) ;
  502. }
  503.  
  504.  
  505. static void
  506. crossWorkspace(WScreen *scr, WWindow *wwin, int opaque_move,
  507.                int new_workspace, int rewind)
  508. {
  509.     /* do not let window be unmapped */
  510.     if (opaque_move) {
  511.     wwin->flags.changing_workspace = 1;
  512.     wWindowChangeWorkspace(wwin, new_workspace);
  513.     }
  514.     /* go to new workspace */
  515.     wWorkspaceChange(scr, new_workspace);
  516.     
  517.     wwin->flags.changing_workspace = 0;
  518.     
  519.     if (rewind)
  520.     XWarpPointer(dpy, None, None, 0, 0, 0, 0, scr->scr_width - 20, 0);
  521.     else
  522.     XWarpPointer(dpy, None, None, 0, 0, 0, 0, -(scr->scr_width - 20), 0);
  523.     
  524.     flushMotion();
  525.     
  526.     if (!opaque_move) {
  527.     XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
  528.              |ButtonReleaseMask|ButtonPressMask, GrabModeAsync,
  529.              GrabModeAsync, None, wCursor[WCUR_MOVE], CurrentTime);
  530.     }
  531. }
  532.  
  533.  
  534.  
  535.  
  536. typedef struct {
  537.     /* arrays of WWindows sorted by the respective border position */
  538.     WWindow **topList;               /* top border */
  539.     WWindow **leftList;               /* left border */
  540.     WWindow **rightList;           /* right border */
  541.     WWindow **bottomList;           /* bottom border */
  542.     int count;
  543.  
  544.     /* index of window in the above lists indicating the relative position
  545.      * of the window with the others */
  546.     int topIndex;
  547.     int leftIndex;
  548.     int rightIndex;
  549.     int bottomIndex;
  550.  
  551.     int rubCount;               /* for workspace switching */
  552.  
  553.     int winWidth, winHeight;           /* width/height of the window */
  554.     int realX, realY;               /* actual position of the window */
  555.     int calcX, calcY;               /* calculated position of window */
  556.     int omouseX, omouseY;           /* old mouse position */
  557.     int mouseX, mouseY;               /* last known position of the pointer */
  558. } MoveData;
  559.  
  560. #define WTOP(w) (w)->frame_y
  561. #define WLEFT(w) (w)->frame_x
  562. #define WRIGHT(w) ((w)->frame_x + (int)(w)->frame->core->width + FRAME_BORDER_WIDTH)
  563. #define WBOTTOM(w) ((w)->frame_y + (int)(w)->frame->core->height + FRAME_BORDER_WIDTH)
  564.  
  565. static int
  566. compareWTop(const void *a, const void *b)
  567. {
  568.     WWindow *wwin1 = *(WWindow**)a;
  569.     WWindow *wwin2 = *(WWindow**)b;
  570.  
  571.     if (WTOP(wwin1) > WTOP(wwin2))
  572.     return -1;
  573.     else if (WTOP(wwin1) < WTOP(wwin2))
  574.     return 1;
  575.     else
  576.     return 0;
  577. }
  578.  
  579.  
  580. static int
  581. compareWLeft(const void *a, const void *b)
  582. {
  583.     WWindow *wwin1 = *(WWindow**)a;
  584.     WWindow *wwin2 = *(WWindow**)b;
  585.  
  586.     if (WLEFT(wwin1) > WLEFT(wwin2))
  587.     return -1;
  588.     else if (WLEFT(wwin1) < WLEFT(wwin2))
  589.     return 1;
  590.     else
  591.     return 0;
  592. }
  593.  
  594.  
  595. static int
  596. compareWRight(const void *a, const void *b)
  597. {
  598.     WWindow *wwin1 = *(WWindow**)a;
  599.     WWindow *wwin2 = *(WWindow**)b;
  600.  
  601.     if (WRIGHT(wwin1) < WRIGHT(wwin2))
  602.     return -1;
  603.     else if (WRIGHT(wwin1) > WRIGHT(wwin2))
  604.     return 1;
  605.     else
  606.     return 0;
  607. }
  608.  
  609.  
  610.  
  611. static int
  612. compareWBottom(const void *a, const void *b)
  613. {
  614.     WWindow *wwin1 = *(WWindow**)a;
  615.     WWindow *wwin2 = *(WWindow**)b;
  616.  
  617.     if (WBOTTOM(wwin1) < WBOTTOM(wwin2))
  618.     return -1;
  619.     else if (WBOTTOM(wwin1) > WBOTTOM(wwin2))
  620.     return 1;
  621.     else
  622.     return 0;
  623. }
  624.  
  625.  
  626. static void
  627. updateResistance(WWindow *wwin, MoveData *data, int newX, int newY)
  628. {
  629.     int i;
  630.     int newX2 = newX + data->winWidth;
  631.     int newY2 = newY + data->winHeight;
  632.     Bool ok = False;
  633.  
  634.     if (newX < data->realX) {
  635.     if (data->rightIndex > 0 
  636.         && newX < WRIGHT(data->rightList[data->rightIndex-1])) {
  637.         ok = True;
  638.     } else if (data->leftIndex <= data->count-1
  639.            && newX2 <= WLEFT(data->leftList[data->leftIndex])) {
  640.         ok = True;
  641.     }
  642.     } else if (newX > data->realX) {
  643.     if (data->leftIndex > 0
  644.         && newX2 > WLEFT(data->leftList[data->leftIndex-1])) {
  645.         ok = True;
  646.     } else if (data->rightIndex <= data->count-1
  647.            && newX >= WRIGHT(data->rightList[data->rightIndex])) {
  648.         ok = True;
  649.     }
  650.     }
  651.  
  652.     if (!ok) {
  653.     if (newY < data->realY) {
  654.         if (data->bottomIndex > 0 
  655.         && newY < WBOTTOM(data->bottomList[data->bottomIndex-1])) {
  656.         ok = True;
  657.         } else if (data->topIndex <= data->count-1
  658.                && newY2 <= WTOP(data->topList[data->topIndex])) {
  659.         ok = True;
  660.         }
  661.     } else if (newY > data->realY) {
  662.         if (data->topIndex > 0
  663.         && newY2 > WTOP(data->topList[data->topIndex-1])) {
  664.         ok = True;
  665.         } else if (data->bottomIndex <= data->count-1
  666.                && newY >= WBOTTOM(data->bottomList[data->bottomIndex])) {
  667.         ok = True;
  668.         }
  669.     }
  670.     }
  671.  
  672.     if (!ok)
  673.     return;
  674.  
  675.     /* TODO: optimize this */
  676.     if (data->realY < WBOTTOM(data->bottomList[0])) {
  677.     data->bottomIndex = 0;
  678.     }
  679.     if (data->realX < WRIGHT(data->rightList[0])) {
  680.     data->rightIndex = 0;
  681.     }
  682.     if ((data->realX + data->winWidth) > WLEFT(data->leftList[0])) {
  683.     data->leftIndex = 0;
  684.     }
  685.     if ((data->realY + data->winHeight) > WTOP(data->topList[0])) {
  686.     data->topIndex = 0;
  687.     }
  688.     for (i = 0; i < data->count; i++) {
  689.     if (data->realY > WBOTTOM(data->bottomList[i])) {
  690.         data->bottomIndex = i + 1;
  691.     }
  692.     if (data->realX > WRIGHT(data->rightList[i])) {
  693.         data->rightIndex = i + 1;
  694.     }
  695.     if ((data->realX + data->winWidth) < WLEFT(data->leftList[i])) {
  696.         data->leftIndex = i + 1;
  697.     }
  698.     if ((data->realY + data->winHeight) < WTOP(data->topList[i])) {
  699.         data->topIndex = i + 1;
  700.     }
  701.     }
  702. }
  703.  
  704.  
  705. static void
  706. freeMoveData(MoveData *data)
  707. {
  708.     if (data->topList)
  709.     free(data->topList);
  710.     if (data->leftList)
  711.     free(data->leftList);
  712.     if (data->rightList)
  713.     free(data->rightList);
  714.     if (data->bottomList)
  715.     free(data->bottomList);
  716. }
  717.  
  718.  
  719. static void
  720. updateMoveData(WWindow *wwin, MoveData *data)
  721. {
  722.     WScreen *scr = wwin->screen_ptr;
  723.     WWindow *tmp;
  724.     int i;
  725.  
  726.     data->count = 0;
  727.     tmp = scr->focused_window;
  728.     while (tmp) {
  729.     if (tmp != wwin && scr->current_workspace == tmp->frame->workspace
  730.         && !tmp->flags.miniaturized
  731.         && !tmp->flags.hidden
  732.         && !tmp->flags.obscured
  733.         && !WFLAGP(tmp, sunken)) {
  734.         data->topList[data->count] = tmp;
  735.         data->leftList[data->count] = tmp;
  736.         data->rightList[data->count] = tmp;
  737.         data->bottomList[data->count] = tmp;
  738.         data->count++;
  739.     }
  740.     tmp = tmp->prev;
  741.     }
  742.  
  743.     if (data->count == 0) {
  744.     data->topIndex = 0;
  745.     data->leftIndex = 0;
  746.     data->rightIndex = 0;
  747.     data->bottomIndex = 0;    
  748.     return;
  749.     }
  750.  
  751.     /*
  752.      * order from closest to the border of the screen to farthest
  753.      */
  754.     qsort(data->topList, data->count, sizeof(WWindow**), compareWTop);
  755.     qsort(data->leftList, data->count, sizeof(WWindow**), compareWLeft);
  756.     qsort(data->rightList, data->count, sizeof(WWindow**), compareWRight);
  757.     qsort(data->bottomList, data->count, sizeof(WWindow**), compareWBottom);
  758.     
  759.     /* figure the position of the window relative to the others */
  760.  
  761.     data->topIndex = -1;
  762.     data->leftIndex = -1;
  763.     data->rightIndex = -1;
  764.     data->bottomIndex = -1;
  765.  
  766.     if (WTOP(wwin) < WBOTTOM(data->bottomList[0])) {
  767.     data->bottomIndex = 0;
  768.     }
  769.     if (WLEFT(wwin) < WRIGHT(data->rightList[0])) {
  770.     data->rightIndex = 0;
  771.     }
  772.     if (WRIGHT(wwin) > WLEFT(data->leftList[0])) {
  773.     data->leftIndex = 0;
  774.     }
  775.     if (WBOTTOM(wwin) > WTOP(data->topList[0])) {
  776.     data->topIndex = 0;
  777.     }
  778.     for (i = 0; i < data->count; i++) {
  779.     if (WTOP(wwin) >= WBOTTOM(data->bottomList[i])) {
  780.         data->bottomIndex = i + 1;
  781.     }
  782.     if (WLEFT(wwin) >= WRIGHT(data->rightList[i])) {
  783.         data->rightIndex = i + 1;
  784.     }
  785.     if (WRIGHT(wwin) <= WLEFT(data->leftList[i])) {
  786.         data->leftIndex = i + 1;
  787.     }
  788.     if (WBOTTOM(wwin) <= WTOP(data->topList[i])) {
  789.         data->topIndex = i + 1;
  790.     }
  791.     }
  792. }
  793.  
  794.  
  795. static void
  796. initMoveData(WWindow *wwin, MoveData *data)
  797. {
  798.     int i;
  799.     WWindow *tmp;
  800.  
  801.     memset(data, 0, sizeof(MoveData));
  802.  
  803.     for (i = 0, tmp = wwin->screen_ptr->focused_window; 
  804.      tmp != NULL;
  805.      tmp = tmp->prev, i++);
  806.  
  807.     if (i > 1) {
  808.     data->topList = wmalloc(sizeof(WWindow*) * i);
  809.     data->leftList = wmalloc(sizeof(WWindow*) * i);
  810.     data->rightList = wmalloc(sizeof(WWindow*) * i);
  811.     data->bottomList = wmalloc(sizeof(WWindow*) * i);
  812.  
  813.     updateMoveData(wwin, data);
  814.     }
  815.  
  816.     data->realX = wwin->frame_x;
  817.     data->realY = wwin->frame_y;
  818.     data->calcX = wwin->frame_x;
  819.     data->calcY = wwin->frame_y;
  820.  
  821.     data->winWidth = wwin->frame->core->width + 2;
  822.     data->winHeight = wwin->frame->core->height + 2;
  823. }
  824.  
  825.  
  826. static Bool
  827. checkWorkspaceChange(WWindow *wwin, MoveData *data, Bool opaqueMove)
  828. {
  829.     WScreen *scr = wwin->screen_ptr;
  830.     Bool changed = False;
  831.  
  832.     if (data->mouseX <= 1) {
  833.     if (scr->current_workspace > 0) {
  834.  
  835.         crossWorkspace(scr, wwin, opaqueMove, scr->current_workspace - 1,
  836.                True);
  837.         changed = True;
  838.         data->rubCount = 0;
  839.  
  840.     } else if (scr->current_workspace == 0 && wPreferences.ws_cycle) {
  841.  
  842.         crossWorkspace(scr, wwin, opaqueMove, scr->workspace_count - 1,
  843.                True);
  844.         changed = True;
  845.         data->rubCount = 0;
  846.     }
  847.     } else if (data->mouseX >= scr->scr_width - 2) {
  848.  
  849.     if (scr->current_workspace == scr->workspace_count - 1) {
  850.  
  851.         if (wPreferences.ws_cycle
  852.         || scr->workspace_count == MAX_WORKSPACES) {
  853.  
  854.         crossWorkspace(scr, wwin, opaqueMove, 0, False);
  855.         changed = True;
  856.         data->rubCount = 0;
  857.         }
  858.         /* if user insists on trying to go to next workspace even when
  859.          * it's already the last, create a new one */
  860.         else if (data->omouseX == data->mouseX 
  861.              && wPreferences.ws_advance) {
  862.  
  863.         /* detect user "rubbing" the window against the edge */
  864.         if (data->rubCount > 0 
  865.             && data->omouseY - data->mouseY > MOVE_THRESHOLD) {
  866.  
  867.             data->rubCount = -(data->rubCount + 1);
  868.  
  869.         } else if (data->rubCount <= 0
  870.                && data->mouseY - data->omouseY > MOVE_THRESHOLD) {
  871.  
  872.             data->rubCount = -data->rubCount + 1;
  873.         }
  874.         }
  875.         /* create a new workspace */
  876.         if (abs(data->rubCount) > 2) {
  877.         /* go to next workspace */
  878.         wWorkspaceNew(scr);
  879.         
  880.         crossWorkspace(scr, wwin, opaqueMove, 
  881.                    scr->current_workspace+1, False);
  882.         changed = True;
  883.         data->rubCount = 0;
  884.         }
  885.     } else if (scr->current_workspace < scr->workspace_count) {
  886.  
  887.         /* go to next workspace */
  888.         crossWorkspace(scr, wwin, opaqueMove, 
  889.                scr->current_workspace+1, False);
  890.         changed = True;
  891.         data->rubCount = 0;
  892.     }
  893.     } else {
  894.     data->rubCount = 0;
  895.     }
  896.  
  897.     return changed;
  898. }
  899.  
  900.  
  901. static void
  902. updateWindowPosition(WWindow *wwin, MoveData *data, Bool doResistance,
  903.              Bool opaqueMove, int newMouseX, int newMouseY)
  904. {
  905.     WScreen *scr = wwin->screen_ptr;
  906.     int dx, dy;                   /* how much mouse moved */
  907.     int winL, winR, winT, winB;           /* requested new window position */
  908.     int newX, newY;               /* actual new window position */
  909.     Bool hresist, vresist;
  910.     Bool updateIndex;
  911.     Bool attract;
  912.  
  913.     hresist = False;
  914.     vresist = False;
  915.  
  916.     updateIndex = False;
  917.  
  918.     /* check the direction of the movement */
  919.     dx = newMouseX - data->mouseX;
  920.     dy = newMouseY - data->mouseY;
  921.  
  922.     data->omouseX = data->mouseX;
  923.     data->omouseY = data->mouseY;
  924.     data->mouseX = newMouseX;
  925.     data->mouseY = newMouseY;
  926.  
  927.     winL = data->calcX + dx;
  928.     winR = data->calcX + data->winWidth + dx;
  929.     winT = data->calcY + dy;
  930.     winB = data->calcY + data->winHeight + dy;
  931.  
  932.     newX = data->realX;
  933.     newY = data->realY;
  934.  
  935.     if (doResistance) {
  936.     int l_edge, r_edge;
  937.     int edge_l, edge_r;
  938.     int t_edge, b_edge;
  939.     int edge_t, edge_b;
  940.     int resist;
  941.  
  942.     resist = WIN_RESISTANCE(wPreferences.edge_resistance);
  943.     attract = wPreferences.attract;
  944.     /* horizontal movement: check horizontal edge resistances */
  945.     if (dx || dy) {
  946.         int i;
  947.         /* window is the leftmost window: check against screen edge */
  948.         l_edge = scr->totalUsableArea.x1;
  949.         r_edge = scr->totalUsableArea.x2 + resist;
  950.         edge_l = scr->totalUsableArea.x1 - resist;
  951.         edge_r = scr->totalUsableArea.x2;
  952.  
  953.         /* 1 */
  954.         if ((data->rightIndex >= 0) && (data->rightIndex <= data->count)) {
  955.         WWindow *looprw;
  956.                         
  957.         for (i = data->rightIndex - 1; i >= 0; i--) {
  958.             looprw = data->rightList[i];
  959.             if (!(data->realY > WBOTTOM(looprw) 
  960.               || (data->realY + data->winHeight) < WTOP(looprw))) {
  961.             if (attract 
  962.                 || ((data->realX < (WRIGHT(looprw) + 2)) && dx < 0)) {
  963.                 l_edge = WRIGHT(looprw) + 1;
  964.                 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
  965.             }
  966.             break;
  967.             }
  968.         }
  969.         
  970.         if (attract) {
  971.             for (i = data->rightIndex; i < data->count; i++) {
  972.             looprw = data->rightList[i];
  973.             if(!(data->realY > WBOTTOM(looprw) 
  974.                  || (data->realY + data->winHeight) < WTOP(looprw))) {
  975.                 r_edge = WRIGHT(looprw) + 1;
  976.                 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
  977.                 break;
  978.             }
  979.             }
  980.         }
  981.         }
  982.         
  983.         if ((data->leftIndex >= 0) && (data->leftIndex <= data->count)) {
  984.         WWindow *looprw;
  985.                         
  986.         for (i = data->leftIndex - 1; i >= 0; i--) {
  987.             looprw = data->leftList[i];
  988.             if (!(data->realY > WBOTTOM(looprw) 
  989.               || (data->realY + data->winHeight) < WTOP(looprw))) {
  990.             if (attract 
  991.                 || (((data->realX + data->winWidth) > (WLEFT(looprw) - 1)) && dx > 0)) {
  992.                 edge_r = WLEFT(looprw);
  993.                 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
  994.             }
  995.             break;
  996.             }
  997.         }
  998.         
  999.         if (attract)
  1000.             for (i = data->leftIndex; i < data->count; i++) {
  1001.             looprw = data->leftList[i];
  1002.             if(!(data->realY > WBOTTOM(looprw) 
  1003.                  || (data->realY + data->winHeight) < WTOP(looprw))) {
  1004.                 edge_l = WLEFT(looprw);
  1005.                 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
  1006.                 break;
  1007.             }
  1008.             }
  1009.         }
  1010.         
  1011.         /*
  1012.         printf("%d %d\n",winL,winR);
  1013.         printf("l_ %d r_ %d _l %d _r %d\n",l_edge,r_edge,edge_l,edge_r);
  1014.         */
  1015.  
  1016.         if ((winL - l_edge) < (r_edge - winL)) {
  1017.         if (resist > 0) {
  1018.             if ((attract && winL <= l_edge + resist && winL >= l_edge - resist)
  1019.             || (dx < 0 && winL <= l_edge && winL >= l_edge - resist)) {
  1020.             newX = l_edge;
  1021.             hresist = True;
  1022.             }
  1023.         }
  1024.         } else {
  1025.         if (resist > 0 && attract && winL >= r_edge - resist && winL <= r_edge + resist) {
  1026.             newX = r_edge;
  1027.             hresist = True;
  1028.         }
  1029.         }
  1030.         
  1031.         if ((winR - edge_l) < (edge_r - winR)) {
  1032.         if (resist > 0 && attract && winR <= edge_l + resist && winR >= edge_l - resist) {
  1033.             newX = edge_l - data->winWidth;
  1034.             hresist = True;
  1035.         }
  1036.         } else {
  1037.         if (resist > 0) {
  1038.             if ((attract && winR >= edge_r - resist && winR <= edge_r + resist) 
  1039.             || (dx > 0 && winR >= edge_r && winR <= edge_r + resist)) {
  1040.             newX = edge_r - data->winWidth;
  1041.             hresist = True;
  1042.             }
  1043.         }
  1044.         }
  1045.  
  1046.         /* VeRT */
  1047.         t_edge = scr->totalUsableArea.y1;
  1048.         b_edge = scr->totalUsableArea.y2 + resist;
  1049.         edge_t = scr->totalUsableArea.y1 - resist;
  1050.         edge_b = scr->totalUsableArea.y2;
  1051.  
  1052.         if ((data->bottomIndex >= 0) && (data->bottomIndex <= data->count)) {
  1053.         WWindow *looprw;
  1054.         
  1055.         for (i = data->bottomIndex - 1; i >= 0; i--) {
  1056.             looprw = data->bottomList[i];
  1057.             if (!(data->realX > WRIGHT(looprw) 
  1058.               || (data->realX + data->winWidth) < WLEFT(looprw))) {
  1059.             if (attract 
  1060.                 || ((data->realY < (WBOTTOM(looprw) + 2)) && dy < 0)) {
  1061.                 t_edge = WBOTTOM(looprw) + 1;
  1062.                 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
  1063.             }
  1064.             break;
  1065.             }
  1066.         }
  1067.         
  1068.         if (attract) {
  1069.             for (i = data->bottomIndex; i < data->count; i++) {
  1070.             looprw = data->bottomList[i];
  1071.             if(!(data->realX > WRIGHT(looprw) 
  1072.                  || (data->realX + data->winWidth) < WLEFT(looprw))) {
  1073.                 b_edge = WBOTTOM(looprw) + 1;
  1074.                 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
  1075.                 break;
  1076.             }
  1077.             }
  1078.         }
  1079.         }
  1080.         
  1081.         if ((data->topIndex >= 0) && (data->topIndex <= data->count)) {
  1082.         WWindow *looprw;
  1083.         
  1084.         for (i = data->topIndex - 1; i >= 0; i--) {
  1085.             looprw = data->topList[i];
  1086.             if (!(data->realX > WRIGHT(looprw) 
  1087.               || (data->realX + data->winWidth) < WLEFT(looprw))) {
  1088.             if (attract 
  1089.                 || (((data->realY + data->winHeight) > (WTOP(looprw) - 1)) && dy > 0)) {
  1090.                 edge_b = WTOP(looprw);
  1091.                 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
  1092.             }
  1093.             break;
  1094.             }
  1095.         }
  1096.         
  1097.         if (attract)
  1098.             for (i = data->topIndex; i < data->count; i++) {
  1099.             looprw = data->topList[i];
  1100.             if(!(data->realX > WRIGHT(looprw) 
  1101.                  || (data->realX + data->winWidth) < WLEFT(looprw))) {
  1102.                 edge_t = WTOP(looprw);
  1103.                 resist = WIN_RESISTANCE(wPreferences.edge_resistance);
  1104.                 break;
  1105.             }
  1106.             }
  1107.         }
  1108.         
  1109.         if ((winT - t_edge) < (b_edge - winT)) {
  1110.         if (resist > 0) {
  1111.             if ((attract && winT <= t_edge + resist && winT >= t_edge - resist)
  1112.             || (dy < 0 && winT <= t_edge && winT >= t_edge - resist)) {
  1113.             newY = t_edge;
  1114.             vresist = True;
  1115.             }
  1116.         }
  1117.         }
  1118.         else {
  1119.         if (resist > 0 && attract && winT >= b_edge - resist && winT <= b_edge + resist) {
  1120.             newY = b_edge;
  1121.             vresist = True;
  1122.         }
  1123.         }
  1124.         
  1125.         if ((winB - edge_t) < (edge_b - winB)) {
  1126.         if (resist > 0 && attract && winB <= edge_t + resist && winB >= edge_t - resist) {
  1127.             newY = edge_t - data->winHeight;
  1128.             vresist = True;
  1129.         }
  1130.         }
  1131.         else {
  1132.         if (resist > 0) {
  1133.             if ((attract && winB >= edge_b - resist && winB <= edge_b + resist) 
  1134.             || (dy > 0 && winB >= edge_b && winB <= edge_b + resist)) {
  1135.             newY = edge_b - data->winHeight;
  1136.             vresist = True;
  1137.             }
  1138.         }
  1139.         }
  1140.     }
  1141.     /* END VeRT */
  1142.     
  1143.     }
  1144.     
  1145.     /* update window position */
  1146.     data->calcX += dx;
  1147.     data->calcY += dy;
  1148.     
  1149.     if (((dx > 0 && data->calcX - data->realX > 0)
  1150.      || (dx < 0 && data->calcX - data->realX < 0)) && !hresist)
  1151.     newX = data->calcX;
  1152.     
  1153.     if (((dy > 0 && data->calcY - data->realY > 0)
  1154.      || (dy < 0 && data->calcY - data->realY < 0)) && !vresist)
  1155.     newY = data->calcY;
  1156.     
  1157.     if (data->realX != newX || data->realY != newY) {
  1158.     
  1159.     if (wPreferences.move_display == WDIS_NEW
  1160.         && !scr->selected_windows) {
  1161.         showPosition(wwin, data->realX, data->realY);
  1162.     }
  1163.     if (opaqueMove) {
  1164.         doWindowMove(wwin, scr->selected_windows,
  1165.              newX - wwin->frame_x,
  1166.              newY - wwin->frame_y);
  1167.     } else {
  1168.         /* erase frames */
  1169.         drawFrames(wwin, scr->selected_windows, 
  1170.                data->realX - wwin->frame_x,
  1171.                data->realY - wwin->frame_y);
  1172.     }
  1173.     
  1174.     if (!scr->selected_windows
  1175.         && wPreferences.move_display == WDIS_FRAME_CENTER) {
  1176.         
  1177.         moveGeometryDisplayCentered(scr, newX + data->winWidth/2, 
  1178.                     newY + data->winHeight/2);
  1179.     }
  1180.     
  1181.     if (!opaqueMove) {
  1182.         /* draw frames */
  1183.         drawFrames(wwin, scr->selected_windows, 
  1184.                newX - wwin->frame_x,
  1185.                newY - wwin->frame_y);
  1186.     }
  1187.     
  1188.     if (!scr->selected_windows) {
  1189.         showPosition(wwin, newX, newY);
  1190.     }
  1191.     }
  1192.     
  1193.     
  1194.     /* recalc relative window position */
  1195.     if (doResistance && (data->realX != newX || data->realY != newY)) {
  1196.     updateResistance(wwin, data, newX, newY);
  1197.     }
  1198.  
  1199.     data->realX = newX;
  1200.     data->realY = newY;
  1201. }
  1202.  
  1203.  
  1204. #define _KS KEY_CONTROL_WINDOW_WEIGHT
  1205.  
  1206. int
  1207. wKeyboardMoveResizeWindow(WWindow *wwin)
  1208. {
  1209.     WScreen *scr = wwin->screen_ptr;
  1210.     Window root = scr->root_win;
  1211.     XEvent event;
  1212.     int w = wwin->frame->core->width;
  1213.     int h = wwin->frame->core->height;
  1214.     int scr_width = wwin->screen_ptr->scr_width;
  1215.     int scr_height = wwin->screen_ptr->scr_height;
  1216.     int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
  1217.     int src_x = wwin->frame_x;
  1218.     int src_y = wwin->frame_y;
  1219.     int done,off_x,off_y,ww,wh;
  1220.     int kspeed = _KS;
  1221.     Time lastTime = 0;
  1222.     KeySym keysym=NoSymbol;
  1223.     int moment=0;
  1224.     KeyCode shiftl,shiftr,ctrll,ctrlmode;
  1225.  
  1226.     shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
  1227.     shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
  1228.     ctrll = XKeysymToKeycode(dpy, XK_Control_L);
  1229.     ctrlmode=done=off_x=off_y=0;
  1230.  
  1231.     XSync(dpy, False);
  1232.     wusleep(10000);
  1233.     XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
  1234.  
  1235.     if (!wwin->flags.selected) {
  1236.         wUnselectWindows(scr);
  1237.     }
  1238.     XGrabServer(dpy);
  1239.     XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
  1240.          |ButtonReleaseMask|ButtonPressMask, GrabModeAsync,
  1241.          GrabModeAsync, None, wCursor[WCUR_DEFAULT], CurrentTime);
  1242.  
  1243.     if (wwin->flags.shaded || scr->selected_windows) {
  1244.         if(scr->selected_windows)
  1245.             drawFrames(wwin,scr->selected_windows,off_x,off_y);
  1246.         else drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
  1247.         if(!scr->selected_windows)
  1248.             mapPositionDisplay(wwin, src_x, src_y, w, h);
  1249.     } else {
  1250.         drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
  1251.     }
  1252.     ww=w;
  1253.     wh=h;
  1254.     while(1) {
  1255.     /*
  1256.      looper.ox=off_x;
  1257.      looper.oy=off_y;
  1258.      */
  1259.     WMMaskEvent(dpy, KeyPressMask | ButtonReleaseMask 
  1260.             | ButtonPressMask | ExposureMask, &event);
  1261.         if (wwin->flags.shaded || scr->selected_windows) {
  1262.         if(scr->selected_windows)
  1263.             drawFrames(wwin,scr->selected_windows,off_x,off_y);
  1264.         else drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
  1265.         /*** I HATE EDGE RESISTANCE - ]d ***/
  1266.     }
  1267.     else {
  1268.         drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
  1269.     }
  1270.  
  1271.     if(ctrlmode)
  1272.         showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
  1273.  
  1274.     XUngrabServer(dpy);
  1275.     XSync(dpy, False);
  1276.  
  1277.     switch (event.type) {
  1278.      case KeyPress:
  1279.         /* accelerate */
  1280.         if (event.xkey.time - lastTime > 50) {
  1281.             kspeed/=(1 + (event.xkey.time - lastTime)/100);
  1282.         } else {
  1283.             if (kspeed < 20) {
  1284.                 kspeed++;
  1285.             }
  1286.         }
  1287.         if (kspeed < _KS) kspeed = _KS;
  1288.         lastTime = event.xkey.time;
  1289.  
  1290.         if (event.xkey.state & ControlMask && !wwin->flags.shaded) {
  1291.             ctrlmode=1;
  1292.             wUnselectWindows(scr);
  1293.         }
  1294.         else {
  1295.             ctrlmode=0;
  1296.         }
  1297.         if (event.xkey.keycode == shiftl || event.xkey.keycode == shiftr) {
  1298.             if (ctrlmode)
  1299.                 cycleGeometryDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh, 0);
  1300.             else
  1301.                 cyclePositionDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
  1302.         }
  1303.         else {
  1304.  
  1305.             keysym = XLookupKeysym(&event.xkey, 0);
  1306.             switch (keysym) {
  1307.              case XK_Return:
  1308.                 done=2;
  1309.                 break;
  1310.              case XK_Escape:
  1311.                 done=1;
  1312.                 break;
  1313.              case XK_Up:
  1314.              case XK_KP_Up:
  1315.              case XK_k:
  1316.                 if (ctrlmode){
  1317.                 if (moment != UP)
  1318.                     h = wh;
  1319.                 h-=kspeed;
  1320.                 moment = UP;
  1321.                 if (h < 1) h = 1;
  1322.                 }
  1323.                 else off_y-=kspeed;
  1324.                 break;
  1325.              case XK_Down:
  1326.              case XK_KP_Down:
  1327.              case XK_j:
  1328.                 if (ctrlmode){
  1329.                 if (moment != DOWN)
  1330.                     h = wh;
  1331.                 h+=kspeed;
  1332.                 moment = DOWN;
  1333.                 }
  1334.                 else off_y+=kspeed;
  1335.                 break;
  1336.              case XK_Left:
  1337.              case XK_KP_Left:
  1338.              case XK_h:
  1339.                 if (ctrlmode) {
  1340.                 if (moment != LEFT)
  1341.                     w = ww;
  1342.                 w-=kspeed;
  1343.                 if (w < 1) w = 1;
  1344.                 moment = LEFT;
  1345.                 }
  1346.                 else off_x-=kspeed;
  1347.                 break;
  1348.              case XK_Right:
  1349.              case XK_KP_Right:
  1350.              case XK_l:
  1351.                 if (ctrlmode) {
  1352.                 if (moment != RIGHT)
  1353.                     w = ww;
  1354.                 w+=kspeed;
  1355.                 moment = RIGHT;
  1356.                 }
  1357.                 else off_x+=kspeed;
  1358.                 break;
  1359.             }
  1360.  
  1361.             ww=w;wh=h;
  1362.             wh-=vert_border;
  1363.             wWindowConstrainSize(wwin, &ww, &wh);
  1364.             wh+=vert_border;
  1365.         
  1366.             if (wPreferences.ws_cycle){
  1367.                 if (src_x + off_x + ww < 20){
  1368.                     if(!scr->current_workspace) {
  1369.                         wWorkspaceChange(scr, scr->workspace_count-1);
  1370.                     }
  1371.                     else wWorkspaceChange(scr, scr->current_workspace-1);
  1372.                     off_x += scr_width;
  1373.                 }
  1374.                 else if (src_x + off_x + 20 > scr_width){
  1375.                     if(scr->current_workspace == scr->workspace_count-1) {
  1376.                         wWorkspaceChange(scr, 0);
  1377.                     }
  1378.                     else wWorkspaceChange(scr, scr->current_workspace+1);
  1379.                     off_x -= scr_width;
  1380.                 }
  1381.             }
  1382.             else {
  1383.                 if (src_x + off_x + ww < 20)
  1384.                     off_x = 20 - ww - src_x;
  1385.                 else if (src_x + off_x + 20 > scr_width)
  1386.                     off_x = scr_width - 20 - src_x;
  1387.             }
  1388.         
  1389.             if (src_y + off_y + wh < 20) {
  1390.                 off_y = 20 - wh - src_y;
  1391.             }
  1392.             else if (src_y + off_y + 20 > scr_height) {
  1393.                 off_y = scr_height - 20 - src_y;
  1394.             }
  1395.         }
  1396.         break;
  1397.      case ButtonPress:
  1398.      case ButtonRelease:
  1399.         done=1;
  1400.         break;
  1401.      default:
  1402.         WMHandleEvent(&event);
  1403.         break;
  1404.     }
  1405.  
  1406.     XGrabServer(dpy);
  1407.     /*xxx*/
  1408.  
  1409.     if (wwin->flags.shaded && !scr->selected_windows){
  1410.         moveGeometryDisplayCentered(scr, src_x+off_x + w/2, src_y+off_y + h/2);
  1411.     } else {
  1412.         if (ctrlmode) {
  1413.         WMUnmapWidget(scr->gview);
  1414.         mapGeometryDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
  1415.         } else if(!scr->selected_windows) {
  1416.         WMUnmapWidget(scr->gview);
  1417.         mapPositionDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh);
  1418.         }
  1419.     }
  1420.     
  1421.     if (wwin->flags.shaded || scr->selected_windows) {
  1422.         if (scr->selected_windows)
  1423.         drawFrames(wwin,scr->selected_windows,off_x,off_y);
  1424.         else 
  1425.         drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
  1426.     } else {
  1427.         drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
  1428.     }
  1429.     
  1430.     
  1431.     if (ctrlmode) {
  1432.         showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
  1433.     } else if(!scr->selected_windows)
  1434.         showPosition(wwin, src_x+off_x, src_y+off_y);
  1435.     /**/
  1436.     
  1437.     if(done){
  1438.         scr->keymove_tick=0;
  1439.         /*
  1440.          WMDeleteTimerWithClientData(&looper);
  1441.          */
  1442.             if (wwin->flags.shaded || scr->selected_windows) {
  1443.             if(scr->selected_windows)
  1444.                 drawFrames(wwin,scr->selected_windows,off_x,off_y);
  1445.             else drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, w, h);
  1446.             }
  1447.             else {
  1448.                 drawTransparentFrame(wwin, src_x+off_x, src_y+off_y, ww, wh);
  1449.             }
  1450.  
  1451.         if (ctrlmode) {
  1452.         showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0);
  1453.         WMUnmapWidget(scr->gview);
  1454.         } else
  1455.         WMUnmapWidget(scr->gview);
  1456.         
  1457.         XUngrabKeyboard(dpy, CurrentTime);
  1458.         XUngrabPointer(dpy, CurrentTime);
  1459.         XUngrabServer(dpy);
  1460.  
  1461.         if(done==2) {
  1462.         if (wwin->flags.shaded || scr->selected_windows) {
  1463.             if (!scr->selected_windows) {
  1464.             wWindowMove(wwin, src_x+off_x, src_y+off_y);
  1465.                 wWindowSynthConfigureNotify(wwin);
  1466.             } else {
  1467.             int i;
  1468.             WMBag *bag = scr->selected_windows;
  1469.             doWindowMove(wwin,scr->selected_windows,off_x,off_y);
  1470.             for (i = 0; i < WMGetBagItemCount(bag); i++) {
  1471.                 wWindowSynthConfigureNotify(WMGetFromBag(bag, i));
  1472.             }
  1473.             }
  1474.         } else {
  1475.             if (wwin->client.width != ww)
  1476.             wwin->flags.user_changed_width = 1;
  1477.             
  1478.             if (wwin->client.height != wh - vert_border)
  1479.             wwin->flags.user_changed_height = 1;
  1480.             
  1481.             wWindowConfigure(wwin, src_x+off_x, src_y+off_y, 
  1482.                      ww, wh - vert_border);
  1483.             wWindowSynthConfigureNotify(wwin);
  1484.         }
  1485.         wWindowChangeWorkspace(wwin, scr->current_workspace);
  1486.         wSetFocusTo(scr, wwin);
  1487.         }
  1488.         return 1;
  1489.     }
  1490.     }
  1491. }
  1492.  
  1493.  
  1494. /*
  1495.  *---------------------------------------------------------------------- 
  1496.  * wMouseMoveWindow--
  1497.  *     Move the named window and the other selected ones (if any),
  1498.  * interactively. Also shows the position of the window, if only one
  1499.  * window is being moved.
  1500.  *     If the window is not on the selected window list, the selected
  1501.  * windows are deselected.
  1502.  *     If shift is pressed during the operation, the position display
  1503.  * is changed to another type.
  1504.  * 
  1505.  * Returns:
  1506.  *     True if the window was moved, False otherwise.
  1507.  * 
  1508.  * Side effects:
  1509.  *     The window(s) position is changed, and the client(s) are 
  1510.  * notified about that.
  1511.  *     The position display configuration may be changed.
  1512.  *---------------------------------------------------------------------- 
  1513.  */
  1514. int
  1515. wMouseMoveWindow(WWindow *wwin, XEvent *ev)
  1516. {
  1517.     WScreen *scr = wwin->screen_ptr;
  1518.     XEvent event;
  1519.     Window root = scr->root_win;
  1520.     KeyCode shiftl, shiftr;
  1521.     Bool done = False;
  1522.     int started = 0;
  1523.     int warped = 0;
  1524.     /* This needs not to change while moving, else bad things can happen */
  1525.     int opaqueMove = wPreferences.opaque_move;
  1526.     MoveData moveData;
  1527. #ifdef GHOST_WINDOW_MOVE
  1528.     RImage *rimg;
  1529.     
  1530.     rimg = InitGhostWindowMove(scr);
  1531. #endif
  1532.  
  1533.  
  1534.     if (wPreferences.opaque_move && !wPreferences.use_saveunders) {
  1535.     XSetWindowAttributes attr;
  1536.  
  1537.     attr.save_under = True;
  1538.     XChangeWindowAttributes(dpy, wwin->frame->core->window,
  1539.                 CWSaveUnder, &attr);
  1540.     }
  1541.  
  1542.  
  1543.     initMoveData(wwin, &moveData);
  1544.  
  1545.     moveData.mouseX = ev->xmotion.x_root;
  1546.     moveData.mouseY = ev->xmotion.y_root;
  1547.  
  1548.     if (!wwin->flags.selected) {
  1549.     /* this window is not selected, unselect others and move only wwin */
  1550.     wUnselectWindows(scr);
  1551.     }
  1552. #ifdef DEBUG
  1553.     puts("Moving window");
  1554. #endif
  1555.     shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
  1556.     shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
  1557.     while (!done) {
  1558.     if (warped) {
  1559.             int junk;
  1560.             Window junkw;
  1561.  
  1562.         /* XWarpPointer() doesn't seem to generate Motion events, so
  1563.          we've got to simulate them */
  1564.         XQueryPointer(dpy, root, &junkw, &junkw, &event.xmotion.x_root,
  1565.               &event.xmotion.y_root, &junk, &junk,
  1566.               (unsigned *) &junk);
  1567.     } else {
  1568.         WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask
  1569.             | PointerMotionHintMask
  1570.             | ButtonReleaseMask | ButtonPressMask | ExposureMask,
  1571.             &event);
  1572.         
  1573.         if (event.type == MotionNotify) {
  1574.         /* compress MotionNotify events */
  1575.         while (XCheckMaskEvent(dpy, ButtonMotionMask, &event)) ;
  1576.         if (!checkMouseSamplingRate(&event))
  1577.             continue;
  1578.         }
  1579.     }
  1580.     switch (event.type) {
  1581.      case KeyPress:
  1582.         if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
  1583.         && started && !scr->selected_windows) {
  1584.  
  1585.         if (!opaqueMove) {
  1586.                     drawFrames(wwin, scr->selected_windows,
  1587.                                moveData.realX - wwin->frame_x,
  1588.                    moveData.realY - wwin->frame_y);
  1589.         }
  1590.  
  1591.         if (wPreferences.move_display == WDIS_NEW
  1592.             && !scr->selected_windows) {
  1593.             showPosition(wwin, moveData.realX, moveData.realY);
  1594.             XUngrabServer(dpy);
  1595.         }
  1596.         cyclePositionDisplay(wwin, moveData.realX, moveData.realY,
  1597.                      moveData.winWidth, moveData.winHeight);
  1598.  
  1599.         if (wPreferences.move_display == WDIS_NEW
  1600.             && !scr->selected_windows) {
  1601.             XGrabServer(dpy);
  1602.             showPosition(wwin, moveData.realX, moveData.realY);
  1603.         }
  1604.  
  1605.         if (!opaqueMove) {
  1606.                     drawFrames(wwin, scr->selected_windows,
  1607.                                moveData.realX - wwin->frame_x,
  1608.                    moveData.realY - wwin->frame_y);
  1609.         }
  1610.         }
  1611.         break;
  1612.         
  1613.      case MotionNotify:
  1614.         if (started) {
  1615.         updateWindowPosition(wwin, &moveData,
  1616.                      scr->selected_windows == NULL
  1617.                      && wPreferences.edge_resistance > 0,
  1618.                      opaqueMove, 
  1619.                      event.xmotion.x_root,
  1620.                      event.xmotion.y_root);
  1621.  
  1622.         if (!warped && !wPreferences.no_autowrap) {
  1623.             int oldWorkspace = scr->current_workspace;
  1624.  
  1625.             if (wPreferences.move_display == WDIS_NEW
  1626.             && !scr->selected_windows) {
  1627.             showPosition(wwin, moveData.realX, moveData.realY);
  1628.             XUngrabServer(dpy);
  1629.             }
  1630.             if (!opaqueMove) {
  1631.             drawFrames(wwin, scr->selected_windows, 
  1632.                    moveData.realX - wwin->frame_x,
  1633.                    moveData.realY - wwin->frame_y);
  1634.             }
  1635.             if (checkWorkspaceChange(wwin, &moveData, opaqueMove)) {
  1636.             if (scr->current_workspace != oldWorkspace
  1637.                 && wPreferences.edge_resistance > 0
  1638.                 && scr->selected_windows == NULL)
  1639.                 updateMoveData(wwin, &moveData);
  1640.             warped = 1;
  1641.             }
  1642.             if (!opaqueMove) {
  1643.             drawFrames(wwin, scr->selected_windows, 
  1644.                    moveData.realX - wwin->frame_x,
  1645.                    moveData.realY - wwin->frame_y);
  1646.             }
  1647.             if (wPreferences.move_display == WDIS_NEW
  1648.             && !scr->selected_windows) {
  1649.             XSync(dpy, False);
  1650.             showPosition(wwin, moveData.realX, moveData.realY);
  1651.             XGrabServer(dpy);
  1652.             }
  1653.         } else {
  1654.             warped = 0;
  1655.         }
  1656.         } else if (abs(ev->xmotion.x_root - event.xmotion.x_root) >= MOVE_THRESHOLD
  1657.                || abs(ev->xmotion.y_root - event.xmotion.y_root) >= MOVE_THRESHOLD) {
  1658.  
  1659.         XChangeActivePointerGrab(dpy, ButtonMotionMask
  1660.                      | ButtonReleaseMask | ButtonPressMask,
  1661.                      wCursor[WCUR_MOVE], CurrentTime);
  1662.         started = 1;
  1663.         XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync,
  1664.                   CurrentTime);
  1665.  
  1666.         if (!scr->selected_windows)
  1667.             mapPositionDisplay(wwin, moveData.realX, moveData.realY,
  1668.                        moveData.winWidth, moveData.winHeight);
  1669.  
  1670.         if (started && !opaqueMove)
  1671.             drawFrames(wwin, scr->selected_windows, 0, 0);
  1672.  
  1673.         if (!opaqueMove || (wPreferences.move_display==WDIS_NEW
  1674.                     && !scr->selected_windows)) {
  1675.             XGrabServer(dpy);
  1676.             if (wPreferences.move_display==WDIS_NEW)
  1677.             showPosition(wwin, moveData.realX, moveData.realY);
  1678.         }
  1679.         }
  1680.         break;
  1681.  
  1682.      case ButtonPress:
  1683.         break;
  1684.         
  1685.      case ButtonRelease:
  1686.         if (event.xbutton.button != ev->xbutton.button)
  1687.         break;
  1688.  
  1689.         if (started) {
  1690.         XEvent e;
  1691.         if (!opaqueMove) {
  1692.             drawFrames(wwin, scr->selected_windows,
  1693.                    moveData.realX - wwin->frame_x,
  1694.                    moveData.realY - wwin->frame_y);
  1695.             XSync(dpy, 0);
  1696.             doWindowMove(wwin, scr->selected_windows,
  1697.                  moveData.realX - wwin->frame_x,
  1698.                  moveData.realY - wwin->frame_y);
  1699.         }
  1700. #ifndef CONFIGURE_WINDOW_WHILE_MOVING
  1701.         wWindowSynthConfigureNotify(wwin);
  1702. #endif
  1703.         XUngrabKeyboard(dpy, CurrentTime);
  1704.         XUngrabServer(dpy);
  1705.         if (!opaqueMove) {
  1706.             wWindowChangeWorkspace(wwin, scr->current_workspace);
  1707.             wSetFocusTo(scr, wwin);
  1708.         }
  1709.         if (wPreferences.move_display == WDIS_NEW)
  1710.             showPosition(wwin, moveData.realX, moveData.realY);
  1711.         
  1712.         /* discard all enter/leave events that happened until
  1713.          * the time the button was released */
  1714.         while (XCheckTypedEvent(dpy, EnterNotify, &e)) {
  1715.             if (e.xcrossing.time > event.xbutton.time) {
  1716.             XPutBackEvent(dpy, &e);
  1717.             break;
  1718.             } 
  1719.         }
  1720.         while (XCheckTypedEvent(dpy, LeaveNotify, &e)) {
  1721.             if (e.xcrossing.time > event.xbutton.time) {
  1722.             XPutBackEvent(dpy, &e);
  1723.             break;
  1724.             }
  1725.         }
  1726.  
  1727.         if (!scr->selected_windows) {
  1728.             /* get rid of the geometry window */
  1729.             WMUnmapWidget(scr->gview);
  1730.         }
  1731.         }
  1732. #ifdef DEBUG
  1733.         puts("End move window");
  1734. #endif
  1735.         done = True;
  1736.         break;
  1737.  
  1738.      default:
  1739.         if (started && !opaqueMove) {
  1740.         drawFrames(wwin, scr->selected_windows, 
  1741.                moveData.realX - wwin->frame_x, 
  1742.                moveData.realY - wwin->frame_y);
  1743.         XUngrabServer(dpy);
  1744.         WMHandleEvent(&event);
  1745.         XSync(dpy, False);
  1746.         XGrabServer(dpy);
  1747.         drawFrames(wwin, scr->selected_windows,
  1748.                moveData.realX - wwin->frame_x,
  1749.                moveData.realY - wwin->frame_y);
  1750.         } else {
  1751.         WMHandleEvent(&event);
  1752.         }
  1753.         break;
  1754.     }
  1755.     }
  1756.  
  1757.     if (wPreferences.opaque_move && !wPreferences.use_saveunders) {
  1758.     XSetWindowAttributes attr;
  1759.  
  1760.  
  1761.     attr.save_under = False;
  1762.     XChangeWindowAttributes(dpy, wwin->frame->core->window,
  1763.                 CWSaveUnder, &attr);
  1764.  
  1765.     }
  1766.  
  1767.     freeMoveData(&moveData);
  1768.  
  1769.     return started;
  1770. }
  1771.  
  1772.  
  1773. #define RESIZEBAR    1
  1774. #define HCONSTRAIN    2
  1775.  
  1776. static int
  1777. getResizeDirection(WWindow *wwin, int x, int y, int dx, int dy, 
  1778.            int flags)
  1779. {
  1780.     int w = wwin->frame->core->width - 1;
  1781.     int cw = wwin->frame->resizebar_corner_width;
  1782.     int dir;
  1783.     
  1784.     /* if not resizing through the resizebar */
  1785.     if (!(flags & RESIZEBAR)) {
  1786.     int xdir = (abs(x) < (wwin->client.width/2)) ? LEFT : RIGHT;
  1787.     int ydir = (abs(y) < (wwin->client.height/2)) ? UP : DOWN;
  1788.     if (abs(dx) < 2 || abs(dy) < 2) {
  1789.         if (abs(dy) > abs(dx))
  1790.         xdir = 0;
  1791.         else
  1792.         ydir = 0;
  1793.     }
  1794.     return (xdir | ydir);
  1795.     }
  1796.     
  1797.     /* window is too narrow. allow diagonal resize */
  1798.     if (cw * 2 >= w) {
  1799.     int ydir;
  1800.  
  1801.     if (flags & HCONSTRAIN)
  1802.         ydir = 0;
  1803.     else
  1804.         ydir = DOWN;
  1805.     if (x < cw)
  1806.         return (LEFT | ydir);
  1807.     else
  1808.         return (RIGHT | ydir);
  1809.     }
  1810.     /* vertical resize */
  1811.     if ((x > cw) && (x < w - cw))
  1812.     return DOWN;
  1813.     
  1814.     if (x < cw)
  1815.     dir = LEFT;
  1816.     else 
  1817.     dir = RIGHT;
  1818.     
  1819.     if ((abs(dy) > 0) && !(flags & HCONSTRAIN))
  1820.     dir |= DOWN;
  1821.     
  1822.     return dir;
  1823. }
  1824.  
  1825.  
  1826. void
  1827. wMouseResizeWindow(WWindow *wwin, XEvent *ev)
  1828. {
  1829.     XEvent event;
  1830.     WScreen *scr = wwin->screen_ptr;
  1831.     Window root = scr->root_win;
  1832.     int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
  1833.     int fw = wwin->frame->core->width;
  1834.     int fh = wwin->frame->core->height;
  1835.     int fx = wwin->frame_x;
  1836.     int fy = wwin->frame_y;
  1837.     int is_resizebar = (wwin->frame->resizebar
  1838.             && ev->xany.window==wwin->frame->resizebar->window);
  1839.     int orig_x, orig_y;
  1840.     int started;
  1841.     int dw, dh;
  1842.     int rw = fw, rh = fh;
  1843.     int rx1, ry1, rx2, ry2;
  1844.     int res = 0;
  1845.     KeyCode shiftl, shiftr;
  1846.     int h = 0;
  1847.     int orig_fx = fx;
  1848.     int orig_fy = fy;
  1849.     int orig_fw = fw;
  1850.     int orig_fh = fh;
  1851.     
  1852.     if (wwin->flags.shaded) {
  1853.     wwarning("internal error: tryein");
  1854.     return;
  1855.     }
  1856.     orig_x = ev->xbutton.x_root;
  1857.     orig_y = ev->xbutton.y_root;
  1858.     
  1859.     started = 0;
  1860. #ifdef DEBUG
  1861.     puts("Resizing window");
  1862. #endif
  1863.     
  1864.     wUnselectWindows(scr);
  1865.     rx1 = fx;
  1866.     rx2 = fx + fw - 1;
  1867.     ry1 = fy;
  1868.     ry2 = fy + fh - 1;
  1869.     shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
  1870.     shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
  1871.     if (!WFLAGP(wwin, no_titlebar))
  1872.         h = WMFontHeight(wwin->screen_ptr->title_font) + (wPreferences.window_title_clearance + TITLEBAR_EXTEND_SPACE) * 2;
  1873.     else
  1874.     h = 0;
  1875.     while (1) {
  1876.     WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask 
  1877.            | ButtonReleaseMask | PointerMotionHintMask
  1878.            | ButtonPressMask | ExposureMask, &event);
  1879.     if (!checkMouseSamplingRate(&event))
  1880.         continue;
  1881.  
  1882.     switch (event.type) {
  1883.      case KeyPress:
  1884.         showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
  1885.         if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
  1886.         && started) {
  1887.         drawTransparentFrame(wwin, fx, fy, fw, fh);
  1888.         cycleGeometryDisplay(wwin, fx, fy, fw, fh, res);
  1889.         drawTransparentFrame(wwin, fx, fy, fw, fh);
  1890.         }
  1891.         showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
  1892.         break;
  1893.         
  1894.      case MotionNotify:
  1895.         if (started) {
  1896.         while (XCheckMaskEvent(dpy, ButtonMotionMask, &event)) ;
  1897.         
  1898.         dw = 0;
  1899.         dh = 0;
  1900.         
  1901.         orig_fx = fx;
  1902.         orig_fy = fy;
  1903.         orig_fw = fw;
  1904.         orig_fh = fh;
  1905.         
  1906.         if (res & LEFT)
  1907.             dw = orig_x - event.xmotion.x_root;
  1908.         else if (res & RIGHT)
  1909.             dw = event.xmotion.x_root - orig_x;
  1910.         if (res & UP)
  1911.             dh = orig_y - event.xmotion.y_root;
  1912.         else if (res & DOWN)
  1913.             dh = event.xmotion.y_root - orig_y;
  1914.         
  1915.         orig_x = event.xmotion.x_root;
  1916.         orig_y = event.xmotion.y_root;
  1917.         
  1918.         rw += dw;
  1919.         rh += dh;
  1920.         fw = rw;
  1921.         fh = rh - vert_border;
  1922.         wWindowConstrainSize(wwin, &fw, &fh);
  1923.         fh += vert_border;
  1924.         if (res & LEFT)
  1925.             fx = rx2 - fw + 1;
  1926.         else if (res & RIGHT)
  1927.             fx = rx1;
  1928.         if (res & UP)
  1929.             fy = ry2 - fh + 1;
  1930.         else if (res & DOWN)
  1931.             fy = ry1;
  1932.         } else if (abs(orig_x - event.xmotion.x_root) >= MOVE_THRESHOLD
  1933.                || abs(orig_y - event.xmotion.y_root) >= MOVE_THRESHOLD) {
  1934.         int tx, ty;
  1935.         Window junkw;
  1936.         int flags;
  1937.         
  1938.         XTranslateCoordinates(dpy, root, wwin->frame->core->window,
  1939.                       orig_x, orig_y, &tx, &ty, &junkw);
  1940.         
  1941.         /* check if resizing through resizebar */
  1942.         if (is_resizebar)
  1943.             flags = RESIZEBAR;
  1944.         else
  1945.             flags = 0;
  1946.  
  1947.         if (is_resizebar && ((ev->xbutton.state & ShiftMask)
  1948.             || abs(orig_y - event.xmotion.y_root) < HRESIZE_THRESHOLD))
  1949.             flags |= HCONSTRAIN;
  1950.  
  1951.         res = getResizeDirection(wwin, tx, ty,
  1952.                      orig_x - event.xmotion.x_root,
  1953.                      orig_y - event.xmotion.y_root, flags);
  1954.  
  1955.         if (res == (UP|LEFT))
  1956.             XChangeActivePointerGrab(dpy, ButtonMotionMask
  1957.                     | ButtonReleaseMask | ButtonPressMask,
  1958.                     wCursor[WCUR_TOPLEFTRESIZE], CurrentTime);
  1959.         else if (res == (UP|RIGHT))
  1960.             XChangeActivePointerGrab(dpy, ButtonMotionMask
  1961.                     | ButtonReleaseMask | ButtonPressMask,
  1962.                     wCursor[WCUR_TOPRIGHTRESIZE], CurrentTime);
  1963.         else if (res == (DOWN|LEFT))
  1964.             XChangeActivePointerGrab(dpy, ButtonMotionMask
  1965.                     | ButtonReleaseMask | ButtonPressMask,
  1966.                     wCursor[WCUR_BOTTOMLEFTRESIZE], CurrentTime);
  1967.         else if (res == (DOWN|RIGHT))
  1968.             XChangeActivePointerGrab(dpy, ButtonMotionMask
  1969.                     | ButtonReleaseMask | ButtonPressMask,
  1970.                     wCursor[WCUR_BOTTOMRIGHTRESIZE], CurrentTime);
  1971.         else if (res == DOWN || res == UP)
  1972.             XChangeActivePointerGrab(dpy, ButtonMotionMask
  1973.                     | ButtonReleaseMask | ButtonPressMask,
  1974.                     wCursor[WCUR_VERTICALRESIZE], CurrentTime);
  1975.         else if (res & (DOWN|UP))
  1976.             XChangeActivePointerGrab(dpy, ButtonMotionMask
  1977.                     | ButtonReleaseMask | ButtonPressMask,
  1978.                     wCursor[WCUR_VERTICALRESIZE], CurrentTime);
  1979.         else if (res & (LEFT|RIGHT))
  1980.             XChangeActivePointerGrab(dpy, ButtonMotionMask
  1981.                     | ButtonReleaseMask | ButtonPressMask,
  1982.                     wCursor[WCUR_HORIZONRESIZE], CurrentTime);
  1983.         
  1984.         XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, 
  1985.                   CurrentTime);
  1986.  
  1987.         XGrabServer(dpy);
  1988.  
  1989.         /* Draw the resize frame for the first time. */
  1990.         mapGeometryDisplay(wwin, fx, fy, fw, fh);
  1991.         
  1992.         drawTransparentFrame(wwin, fx, fy, fw, fh);
  1993.         
  1994.         showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
  1995.         
  1996.         started = 1;
  1997.         }
  1998.         if (started) {
  1999.         if (wPreferences.size_display == WDIS_FRAME_CENTER) {
  2000.             drawTransparentFrame(wwin, orig_fx, orig_fy,
  2001.                      orig_fw, orig_fh);
  2002.             moveGeometryDisplayCentered(scr, fx + fw / 2, fy + fh / 2);
  2003.             drawTransparentFrame(wwin, fx, fy, fw, fh);
  2004.         } else {
  2005.             drawTransparentFrame(wwin, orig_fx, orig_fy,
  2006.                      orig_fw, orig_fh);
  2007.             drawTransparentFrame(wwin, fx, fy, fw, fh);
  2008.         }
  2009.         if (fh != orig_fh || fw != orig_fw) {
  2010.             if (wPreferences.size_display == WDIS_NEW) {
  2011.             showGeometry(wwin, orig_fx, orig_fy, orig_fx + orig_fw, 
  2012.                      orig_fy + orig_fh, res);
  2013.             }
  2014.             showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
  2015.         }
  2016.         }
  2017.         break;
  2018.  
  2019.      case ButtonPress:
  2020.         break;
  2021.  
  2022.       case ButtonRelease:
  2023.         if (event.xbutton.button != ev->xbutton.button)
  2024.         break;
  2025.  
  2026.         if (started) {
  2027.         showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
  2028.  
  2029.         drawTransparentFrame(wwin, fx, fy, fw, fh);
  2030.  
  2031.         XUngrabKeyboard(dpy, CurrentTime);
  2032.         WMUnmapWidget(scr->gview);
  2033.         XUngrabServer(dpy);
  2034.         
  2035.         if (wwin->client.width != fw)
  2036.             wwin->flags.user_changed_width = 1;
  2037.  
  2038.         if (wwin->client.height != fh - vert_border)
  2039.             wwin->flags.user_changed_height = 1;
  2040.  
  2041.         wWindowConfigure(wwin, fx, fy, fw, fh - vert_border);
  2042.         }
  2043. #ifdef DEBUG
  2044.         puts("End resize window");
  2045. #endif
  2046.         return;
  2047.         
  2048.      default:
  2049.         WMHandleEvent(&event);
  2050.     }
  2051.     }
  2052. }
  2053.  
  2054. #undef LEFT
  2055. #undef RIGHT
  2056. #undef HORIZONTAL
  2057. #undef UP
  2058. #undef DOWN
  2059. #undef VERTICAL
  2060. #undef HCONSTRAIN
  2061. #undef RESIZEBAR
  2062.  
  2063. void
  2064. wUnselectWindows(WScreen *scr)
  2065. {
  2066.     WWindow *wwin;
  2067.  
  2068.     if (!scr->selected_windows)
  2069.     return;
  2070.     
  2071.     while (WMGetBagItemCount(scr->selected_windows)) {
  2072.     WMBagIterator dummy;
  2073.     
  2074.     wwin = WMBagFirst(scr->selected_windows, &dummy);
  2075.         if (wwin->flags.miniaturized && wwin->icon && wwin->icon->selected)
  2076.             wIconSelect(wwin->icon);
  2077.  
  2078.     wSelectWindow(wwin, False);
  2079.     }
  2080.     WMFreeBag(scr->selected_windows);
  2081.     scr->selected_windows = NULL;
  2082. }
  2083.  
  2084. #ifndef LITE
  2085. static void
  2086. selectWindowsInside(WScreen *scr, int x1, int y1, int x2, int y2)
  2087. {
  2088.     WWindow *tmpw;
  2089.     
  2090.     /* select the windows and put them in the selected window list */
  2091.     tmpw = scr->focused_window;
  2092.     while (tmpw != NULL) {
  2093.     if (!(tmpw->flags.miniaturized || tmpw->flags.hidden)) {
  2094.         if ((tmpw->frame->workspace == scr->current_workspace
  2095.          || IS_OMNIPRESENT(tmpw))
  2096.         && (tmpw->frame_x >= x1) && (tmpw->frame_y >= y1) 
  2097.         && (tmpw->frame->core->width + tmpw->frame_x <= x2)
  2098.         && (tmpw->frame->core->height + tmpw->frame_y <= y2)) {
  2099.         wSelectWindow(tmpw, True);
  2100.         }
  2101.     }
  2102.     tmpw = tmpw->prev;
  2103.     }
  2104. }
  2105.  
  2106.  
  2107. void
  2108. wSelectWindows(WScreen *scr, XEvent *ev)
  2109. {
  2110.     XEvent event;
  2111.     Window root = scr->root_win;
  2112.     GC gc = scr->frame_gc;
  2113.     int xp = ev->xbutton.x_root;
  2114.     int yp = ev->xbutton.y_root;
  2115.     int w = 0, h = 0;
  2116.     int x = xp, y = yp;
  2117.     
  2118. #ifdef DEBUG
  2119.     puts("Selecting windows");
  2120. #endif
  2121.     if (XGrabPointer(dpy, scr->root_win, False, ButtonMotionMask
  2122.              | ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
  2123.              GrabModeAsync, None, wCursor[WCUR_DEFAULT],
  2124.              CurrentTime) != Success) {
  2125.     return;
  2126.     }
  2127.     XGrabServer(dpy);
  2128.     
  2129.     wUnselectWindows(scr);
  2130.     
  2131.     XDrawRectangle(dpy, root, gc, xp, yp, w, h);
  2132.     while (1) {
  2133.     WMMaskEvent(dpy, ButtonReleaseMask | PointerMotionMask
  2134.             | ButtonPressMask, &event);
  2135.     
  2136.     switch (event.type) {
  2137.      case MotionNotify:
  2138.         XDrawRectangle(dpy, root, gc, x, y, w, h);
  2139.         x = event.xmotion.x_root;
  2140.         if (x < xp) {
  2141.         w = xp - x;
  2142.         } else {
  2143.         w = x - xp;
  2144.         x = xp;
  2145.         }
  2146.         y = event.xmotion.y_root;
  2147.         if (y < yp) {
  2148.         h = yp - y;
  2149.         } else {
  2150.         h = y - yp;
  2151.         y = yp;
  2152.         }
  2153.         XDrawRectangle(dpy, root, gc, x, y, w, h);
  2154.         break;
  2155.  
  2156.      case ButtonPress:
  2157.         break;
  2158.  
  2159.      case ButtonRelease:
  2160.         if (event.xbutton.button != ev->xbutton.button)
  2161.         break;
  2162.  
  2163.         XDrawRectangle(dpy, root, gc, x, y, w, h);
  2164.         XUngrabServer(dpy);
  2165.         XUngrabPointer(dpy, CurrentTime);
  2166.         selectWindowsInside(scr, x, y, x + w, y + h);
  2167.        
  2168. #ifdef KWM_HINTS
  2169.         wKWMSelectRootRegion(scr, xp, yp, w, h, 
  2170.                  event.xbutton.state & ControlMask);
  2171. #endif /* KWM_HINTS */
  2172.  
  2173. #ifdef DEBUG
  2174.         puts("End window selection");
  2175. #endif
  2176.         return;
  2177.         
  2178.      default:
  2179.         WMHandleEvent(&event);
  2180.         break;
  2181.     }
  2182.     }
  2183. }
  2184. #endif /* !LITE */
  2185.  
  2186. void
  2187. InteractivePlaceWindow(WWindow *wwin, int *x_ret, int *y_ret,
  2188.                unsigned width, unsigned height)
  2189. {
  2190.     WScreen *scr = wwin->screen_ptr;
  2191.     Window root = scr->root_win;
  2192.     int x, y, h = 0;
  2193.     XEvent event;
  2194.     KeyCode shiftl, shiftr;
  2195.     Window junkw;
  2196.     int junk;
  2197.     
  2198.     if (XGrabPointer(dpy, root, True, PointerMotionMask | ButtonPressMask,
  2199.              GrabModeAsync, GrabModeAsync, None, 
  2200.              wCursor[WCUR_DEFAULT], CurrentTime) != Success) {
  2201.     *x_ret = 0;
  2202.     *y_ret = 0;
  2203.     return;
  2204.     }
  2205.     if (!WFLAGP(wwin, no_titlebar)) {
  2206.     h = WMFontHeight(scr->title_font) + (wPreferences.window_title_clearance + TITLEBAR_EXTEND_SPACE) * 2;
  2207.     height += h;
  2208.     }
  2209.     if (!WFLAGP(wwin, no_resizebar)) {
  2210.     height += RESIZEBAR_HEIGHT;
  2211.     }
  2212.     XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
  2213.     XQueryPointer(dpy, root, &junkw, &junkw, &x, &y, &junk, &junk, 
  2214.           (unsigned *) &junk);
  2215.     mapPositionDisplay(wwin, x - width/2, y - h/2, width, height);
  2216.     
  2217.     drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
  2218.     
  2219.     shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
  2220.     shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
  2221.     while (1) {
  2222.     WMMaskEvent(dpy, PointerMotionMask|ButtonPressMask|ExposureMask|KeyPressMask,
  2223.            &event);
  2224.     
  2225.     if (!checkMouseSamplingRate(&event))
  2226.             continue;
  2227.     
  2228.     switch (event.type) {
  2229.      case KeyPress:
  2230.         if ((event.xkey.keycode == shiftl) 
  2231.         || (event.xkey.keycode == shiftr)) {
  2232.         drawTransparentFrame(wwin,
  2233.                      x - width/2, y - h/2, width, height);
  2234.         cyclePositionDisplay(wwin,
  2235.                      x - width/2, y - h/2, width, height);
  2236.         drawTransparentFrame(wwin,
  2237.                      x - width/2, y - h/2, width, height);
  2238.         }
  2239.         break;
  2240.         
  2241.      case MotionNotify:
  2242.         drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
  2243.         
  2244.         x = event.xmotion.x_root;
  2245.         y = event.xmotion.y_root;
  2246.         
  2247.         if (wPreferences.move_display == WDIS_FRAME_CENTER)
  2248.         moveGeometryDisplayCentered(scr, x, y + (height - h) / 2);
  2249.         
  2250.         showPosition(wwin, x - width/2, y - h/2);
  2251.         
  2252.         drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
  2253.         
  2254.         break;
  2255.         
  2256.      case ButtonPress:
  2257.         drawTransparentFrame(wwin, x - width/2, y - h/2, width, height);
  2258.         XSync(dpy, 0);
  2259.         *x_ret = x - width/2;
  2260.         *y_ret = y - h/2;
  2261.         XUngrabPointer(dpy, CurrentTime);
  2262.         XUngrabKeyboard(dpy, CurrentTime);
  2263.         /* get rid of the geometry window */
  2264.         WMUnmapWidget(scr->gview);
  2265.         return;
  2266.         
  2267.      default:
  2268.         WMHandleEvent(&event);
  2269.         break;
  2270.     }
  2271.     }
  2272. }
  2273.